#include "cellContainer.h"
#include <string>
#include <iostream>
#include <random>
#include <Windows.h>
#include <ctime>
#define FREEGLUT_STATIC
#include "gl\glut.h"
using namespace std;
typedef cellContainer<2, int> cc2d;
typedef cc2d::Cell c2d;
cc2d * _pall;
int sz[3] = { 100, 100};
bool resetState = true;
bool bstop = false;
int waitTime = 10;
int timerInts[] = {
	0,
	1,
	5,
	10,
	25,
	50,
	100
};

void display(void)
{
	cc2d & _all = *_pall;

	glClear(GL_COLOR_BUFFER_BIT);
	double dx = 2.0 / sz[0];
	double dy = 2.0 / sz[1];
	double hw = 0.4 * dx;
	double hh = 0.4 * dy;

	for (auto & c : _all.m_cellContainer)
	{
		int i = c->pos[0];
		int j = c->pos[1];
		int state =c->state;
		if (state == 1) glColor3f(0.2, 0.6, 0.2);
		else glColor3f(0.1, 0.1, 0.1);
		double cx = i * dx + dx * 0.5  - 1;
		double cy = j * dy + dy * 0.5  - 1;
		
		glRectf(
			cx - hw, cy - hh,
			cx + hw, cy + hh
			);
	}
	
	glFlush();

}

auto nextStatFun = [](const int & s, size_t t, cc2d::sf* p){
	int l = 0;
	int d = 0;
	for (int i = 0; i < t; i++)
	{
		if (p[i].state == 1) l++;
		else d++;
	}
	if (s == 1)
	{
		if (l > 3) return 0;
		if (l <= 1) return 0;
		return s;
	}
	else
	{
		if (l == 3) return 1;
		return s;
	}

};
int resetMid = 2;
auto resetStatFun = [](c2d  * p){
	return ((std::rand() * p->pos[0] + p->pos[1]) % resetMid) == 0;
};

void timer_func(int which)
{
	cc2d & _all = *_pall;
	if (resetState)
	{
		_all.reset(resetStatFun);
		resetState = false;
	}
	else
	{
		_all.runStep(nextStatFun);
	}
	glutPostRedisplay();
	if (!bstop)
	{
		glutTimerFunc(waitTime, timer_func, which);
	}
}

void createWaitTimeMenuEntries()
{
	int i;
	for (i = 0; i < sizeof(timerInts) / sizeof(*timerInts); i++)
	{
		char temp[10] = { '\0' };
		if (timerInts[i] == waitTime)
			sprintf_s(temp, "%4d ms *", timerInts[i]);
		else
			sprintf_s(temp, "%4d ms", timerInts[i]);

		glutAddMenuEntry(temp, timerInts[i]);
	}
}
void updateMenuEntries()
{
	int i;
	for (i = 0; i < sizeof(timerInts) / sizeof(*timerInts); i++)
	{
		char temp[10] = { '\0' };
		if (timerInts[i] == waitTime)
			sprintf_s(temp, "%4d ms *", timerInts[i]);
		else
			sprintf_s(temp, "%4d ms", timerInts[i]);

		glutChangeToMenuEntry(i + 1, temp, timerInts[i]);
	}
}

int menuID, subMenuWaitTime;
void MenuWaitTime(int timerInt)
{
	waitTime = timerInt;
	glutSetMenu(subMenuWaitTime);
	updateMenuEntries();
}

void resetStop()
{
	if (bstop)	glutChangeToMenuEntry(2, "run", 1);
	else	glutChangeToMenuEntry(2, "stop", 1);
}

void MenuStopOrReset(int i)
{
	if (i == 1)
	{
		bstop = !bstop;
		if (!bstop)
		{
			glutTimerFunc(waitTime, timer_func, 1);
		}
		resetStop();
	}
	else if (i == 2)
	{
		resetState = true;
		if (!bstop)
		{
			bstop = true;
			resetStop();
		}
		std::srand(std::time(nullptr));
		timer_func(1);

	}
	else
	{
		resetMid = i - 1;
		MenuStopOrReset(2);
	}
}

int main(int argc, char *argv[])
{	
	std::srand(std::time(nullptr)); 
	_pall = new cc2d(sz, [](c2d  * p){return std::rand()%2; });
	cc2d & _all = *_pall;
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(800, 800);
	glutCreateWindow("LifeGame");
	glutDisplayFunc(&display);
	glutTimerFunc(waitTime, timer_func, 1);

	subMenuWaitTime = glutCreateMenu(MenuWaitTime);
	createWaitTimeMenuEntries();

	menuID = glutCreateMenu(MenuStopOrReset);
	glutAddSubMenu("SetTimer", subMenuWaitTime);
	glutAddMenuEntry("stop", 1);
	glutAddMenuEntry("reset", 2);
	glutAddMenuEntry("reset 2", 3);
	glutAddMenuEntry("reset 3", 4);
	glutAddMenuEntry("reset 4", 5);
	glutAddMenuEntry("reset 5", 6);
	glutAddMenuEntry("reset 6", 7);
	glutAddMenuEntry("reset 7", 8);
	glutAddMenuEntry("reset 8", 9);
	glutAddMenuEntry("reset 9", 10);

	glutAttachMenu(GLUT_RIGHT_BUTTON);

	glutMainLoop();
	return 0;
}
